package bp.tools;

import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.*;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;


import bp.difference.SystemConfig;
import microsoft.exchange.webservices.data.core.ExchangeService;
import microsoft.exchange.webservices.data.core.PropertySet;
import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
import microsoft.exchange.webservices.data.core.enumeration.property.time.DayOfTheWeek;
import microsoft.exchange.webservices.data.core.enumeration.property.time.DayOfTheWeekIndex;
import microsoft.exchange.webservices.data.core.enumeration.service.ConflictResolutionMode;
import microsoft.exchange.webservices.data.core.enumeration.service.SendInvitationsMode;
import microsoft.exchange.webservices.data.core.enumeration.service.SendInvitationsOrCancellationsMode;
import microsoft.exchange.webservices.data.core.service.item.Appointment;
import microsoft.exchange.webservices.data.core.service.item.Item;
import microsoft.exchange.webservices.data.core.service.schema.ItemSchema;
import microsoft.exchange.webservices.data.credential.ExchangeCredentials;
import microsoft.exchange.webservices.data.credential.WebCredentials;
import microsoft.exchange.webservices.data.property.complex.ItemId;
import microsoft.exchange.webservices.data.property.complex.MessageBody;
import microsoft.exchange.webservices.data.property.complex.recurrence.pattern.Recurrence;
import microsoft.exchange.webservices.data.property.complex.time.OlsonTimeZoneDefinition;

/**
 * 发送outlook日历
 */
public class EmailToOutLookCalendarUtils {
	public static final String IS_OK = "isOk";
	public static final String IS_ERROR_MESSAGE = "errorMessage";
	public static final String IS_OK_MESSAGE = "okMessage";
	 //@Test
	public void sendMailTest() {

		MessageInfo messageInfo = new MessageInfo();
		messageInfo.setEmailAccount("FS-QMS");
		messageInfo.setEmailPassword("FulScience.2025");
		messageInfo.setSubject("测试outlook日历");
		messageInfo.setBodyMessage("测试outlook日历测试outlook日历测试outlook日历测试outlook日历测试outlook日历测试outlook日历");
		messageInfo.setLocation("第一会议室");
		messageInfo.setStartTime("2025-05-14 13:35:00");
		messageInfo.setEndTime("2025-05-14 13:40:00");
		List<String> list = new ArrayList<>();
		list.add("FS-QMS@fulscience.com");
		messageInfo.setEmailTo(list);
		// 发送
		Map<String,String>  mapmsg=  sendEmailToOutLook(messageInfo);
		System.out.println("itemid ==> " + mapmsg.get(IS_OK_MESSAGE));

		// 取消会议
		//int isok = cancelEmailToOutLook(messageInfo.getEmailAccount(), messageInfo.getEmailPassword(), itemId, "不开会了不开会了");
		//System.out.println("isok  ==>  " + isok);

	}

	/*
	 * 发送邮件
	 */
	public  static Map<String, String> sendMail(String subject,String bodyMessage,String location,String startTime,String endtime,List<String> sendToEmail) {

		MessageInfo messageInfo = new MessageInfo();
		messageInfo.setEmailAccount(SystemConfig.getAppSettings().get("OutLookAccount").toString());
		messageInfo.setEmailPassword(SystemConfig.getAppSettings().get("OutLookPassword").toString());
		messageInfo.setSubject(subject);
		messageInfo.setBodyMessage(bodyMessage);
		messageInfo.setLocation(location);
		messageInfo.setStartTime(startTime);
		messageInfo.setEndTime(endtime);
		messageInfo.setEmailTo(sendToEmail);
		// 发送日历
//		String itemId = sendEmailToOutLook(messageInfo);
//		System.out.println("itemid ==> " + itemId);

		messageInfo.setEmailFrom(SystemConfig.getAppSettings().get("OutLookEmailFrom").toString());

		//发送邮件
		Map<String,String> mapmsg = sendOrdinaryMail(messageInfo);
		// 取消会议  itemId用于取消日历时使用
//		int isok = cancelEmailToOutLook(messageInfo.getEmailAccount(), messageInfo.getEmailPassword(), itemId, "不开会了不开会了");
//		System.out.println("isok  ==>  " + isok);
		return  mapmsg;
	}
	/*
	 * 抄送邮件
	 */
	public  static Map<String,String> sendCCMail(String subject,String bodyMessage,String location,String startTime,String endtime,List<String> sendToEmail) {

		MessageInfo messageInfo = new MessageInfo();
		messageInfo.setEmailAccount(SystemConfig.getAppSettings().get("OutLookAccount").toString());
		messageInfo.setEmailPassword(SystemConfig.getAppSettings().get("OutLookPassword").toString());
		messageInfo.setSubject(subject);
		messageInfo.setBodyMessage(bodyMessage);
		messageInfo.setLocation(location);
		messageInfo.setStartTime(startTime);
		messageInfo.setEndTime(endtime);
		messageInfo.setEmailTo(sendToEmail);
		messageInfo.setEmailFrom(SystemConfig.getAppSettings().get("OutLookEmailFrom").toString());
		//发送抄送邮件
		Map<String,String> mapmsg = sendCCToMail(messageInfo);
		return  mapmsg;
	}
	/*
	 * 发送日历
	 */
	public  static Map<String,String> sendCalendar(String subject,String bodyMessage,String location,String startTime,String endtime,List<String> sendToEmail,
			List<String> optionalEmailTo,List<String> ccemailTolist) {

		MessageInfo messageInfo = new MessageInfo();
		messageInfo.setEmailAccount(SystemConfig.getAppSettings().get("OutLookAccount").toString());
		messageInfo.setEmailPassword(SystemConfig.getAppSettings().get("OutLookPassword").toString());
		messageInfo.setSubject(subject);
		messageInfo.setBodyMessage(bodyMessage);
		messageInfo.setLocation(location);
		messageInfo.setStartTime(startTime);
		messageInfo.setEndTime(endtime);
		messageInfo.setEmailTo(sendToEmail);
		messageInfo.setCcEmailTo(ccemailTolist);
		messageInfo.setOptionalEmailTo(optionalEmailTo);
		// 发送日历
		Map<String, String> sgmap = sendEmailToOutLook(messageInfo);
		System.out.println("itemid ==> " + sgmap.get("IS_OK_MESSAGE"));
		//发送邮件
//		int isok = sendOrdinaryMail(messageInfo);
		// 取消会议  itemId用于取消日历时使用
//		int isok = cancelEmailToOutLook(messageInfo.getEmailAccount(), messageInfo.getEmailPassword(), itemId, "不开会了不开会了");
//		System.out.println("isok  ==>  " + isok);
		return sgmap;
	}
	/*
	 * 发送邮件且同时发送日历
	 */
	public  static Map<String, String> sendMailCan(String subject,String bodyMessage,String location,String startTime,
												   String endtime,List<String> sendToEmail,List<String> optionalEmailTo,List<String> ccemailTolist) {

		MessageInfo messageInfo = new MessageInfo();
		messageInfo.setEmailAccount(SystemConfig.getAppSettings().get("OutLookAccount").toString());
		messageInfo.setEmailPassword(SystemConfig.getAppSettings().get("OutLookPassword").toString());
		messageInfo.setSubject(subject);
		messageInfo.setBodyMessage(bodyMessage);
		messageInfo.setLocation(location);
		messageInfo.setStartTime(startTime);
		messageInfo.setEndTime(endtime);
		messageInfo.setEmailTo(sendToEmail);
		messageInfo.setCcEmailTo(ccemailTolist);
		messageInfo.setOptionalEmailTo(optionalEmailTo);
		// 发送日历
		Map<String, String> sgmap = sendEmailToOutLook(messageInfo);
		System.out.println("itemid ==> " + sgmap.get("IS_OK_MESSAGE"));

		messageInfo.setEmailFrom(SystemConfig.getAppSettings().get("OutLookEmailFrom").toString());
		//发送邮件
		sendOrdinaryMail(messageInfo);
		// 取消会议  itemId用于取消日历时使用
//		int isok = cancelEmailToOutLook(messageInfo.getEmailAccount(), messageInfo.getEmailPassword(), itemId, "不开会了不开会了");
//		System.out.println("isok  ==>  " + isok);
		return sgmap;
	}
	/**
	 * 发送普通邮件
	 * 
	 * https://blog.csdn.net/qqheheqq/article/details/16805195
	 */
	public static Map sendOrdinaryMail(MessageInfo messageInfo) {

		Map<String, String> msgMap = new HashMap<>();
		msgMap.put(IS_OK, "0"); //  0 : 成功 ， 1：失败
		msgMap.put(IS_ERROR_MESSAGE, "");
		try {
			Properties prop = System.getProperties();
			prop.put("mail.smtp.host", "mail.fulscience.com");
			prop.put("mail.smtp.auth", true);
			prop.put("mail.smtp.port", 25);
			prop.put("mail.smtp.starttls.enable", false);

			// 这里必须置空，防止同一个方法里多次调用发送邮件功能，第一次发送成功，后面的都会失败
			Session session = null;
			 session = Session.getInstance(prop, new Authenticator() {
				protected PasswordAuthentication getPasswordAuthentication() {
					return new PasswordAuthentication(messageInfo.getEmailAccount(), messageInfo.getEmailPassword());
				}
			});

			Message message = new MimeMessage(session);
			message.setFrom(new InternetAddress(messageInfo.getEmailFrom()));
			// 各一个人发送邮件
			// message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(messageInfo.getEmailTo()));

			// 给 多个人 发送邮件
			List<String> temp = null;
			if (messageInfo.getEmailTo() == null) {
				temp = new ArrayList<>();
				messageInfo.setEmailTo(temp);
			}

			// 给一批人发送邮件
			Address[] tos = new InternetAddress[messageInfo.getEmailTo().size()];
			//
			List<String> emailList = messageInfo.getEmailTo();
			for (int ii = 0; ii < emailList.size(); ii++) {
				tos[ii] = new InternetAddress(emailList.get(ii));
			}

			message.setRecipients(Message.RecipientType.TO, tos);

			// 给抄送人发送邮件
			List<String> ccEmailTo = messageInfo.getCcEmailTo();
			if (ccEmailTo != null && ccEmailTo.size() > 0) {
				Address[] ccs = new InternetAddress[ccEmailTo.size()];

				for (int yy = 0; yy < ccEmailTo.size(); yy++) {
					ccs[yy] = new InternetAddress(ccEmailTo.get(yy));
				}

				message.setRecipients(Message.RecipientType.CC, ccs);
			}

			message.setSubject(messageInfo.getSubject());
//			message.setText(messageInfo.getBodyMessage());
			message.setContent(messageInfo.getBodyMessage(), "text/html; charset=utf-8"); // 展示html页面格式
			Transport.send(message);

		} catch (Exception e) {
			msgMap.put(IS_OK, "1"); //  0 : 成功 ， 1：失败
			msgMap.put(IS_ERROR_MESSAGE, e.getMessage());
		}
		return msgMap;
	}
	/**
	 * 抄送邮件
	 *
	 * https://blog.csdn.net/qqheheqq/article/details/16805195
	 */
	public static Map<String, String> sendCCToMail(MessageInfo messageInfo) {

		Map<String, String> msgMap = new HashMap<>();
		msgMap.put(IS_OK, "0"); //  0 : 成功 ， 1：失败
		msgMap.put(IS_ERROR_MESSAGE, "");
		try {

			Properties prop = System.getProperties();
			prop.put("mail.smtp.host", "mail.fulscience.com");
			prop.put("mail.smtp.auth", true);
			prop.put("mail.smtp.port", 25);
			prop.put("mail.smtp.starttls.enable", false);

			Session session = Session.getInstance(prop, new Authenticator() {
				protected PasswordAuthentication getPasswordAuthentication() {
					return new PasswordAuthentication(messageInfo.getEmailAccount(), messageInfo.getEmailPassword());
				}
			});

			Message message = new MimeMessage(session);
			message.setFrom(new InternetAddress(messageInfo.getEmailFrom()));
			// 各一个人发送邮件
			// message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(messageInfo.getEmailTo()));

			// 给一批人发送邮件
			Address[] tos = new InternetAddress[messageInfo.getEmailTo().size()];

			List<String> emailList = messageInfo.getEmailTo();
			for (int ii = 0; ii < emailList.size(); ii++) {
				tos[ii] = new InternetAddress(emailList.get(ii));
			}

			message.setRecipients(Message.RecipientType.CC, tos);
			message.setSubject(messageInfo.getSubject());
			message.setContent(messageInfo.getBodyMessage(), "text/html; charset=utf-8"); // 展示html页面格式
			Transport.send(message);

		} catch (Exception e) {
			msgMap.put(IS_OK, "1"); //  0 : 成功 ， 1：失败
			msgMap.put(IS_ERROR_MESSAGE, e.getMessage());
		}
		return msgMap;
	}
	/**
	 * 发送邮件 到 outlook 日历
	 */
	public static Map<String, String> sendEmailToOutLook(MessageInfo messageInfo) {
		// 初始化
		ExchangeService exchangeService = initExchange(messageInfo.getEmailAccount(), messageInfo.getEmailPassword());
		// 发送 outlook 到日历
		Map<String, String> msgMap = sendMeetBook(exchangeService, messageInfo);

		return msgMap;
	}

	/**
	 * 取消 outlook 日历
	 */
	public static int cancelEmailToOutLook(String emailAccount, String emailPassword, String itemId, String cancelReason) {
		// 初始化
		ExchangeService exchangeService = initExchange(emailAccount, emailPassword);
		// 取消会议
		int isOK = cancelMeetBook(exchangeService, itemId, cancelReason);
		//
		return isOK;
	}

	/**
	 * 发送outlook日历
	 *
	 * @param userName：发送人邮箱账号
	 * @param password：发送人邮箱密码
	 * @return
	 */
	private static ExchangeService initExchange(String userName, String password) {
		// 与exchange web服务器建立连接
		ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);

		ExchangeCredentials credentials = new WebCredentials(userName, password);
		service.setCredentials(credentials);
		// 这个url可能每个公司不一样，大多数是这个
		service.setUrl(URI.create(SystemConfig.getAppSettings().get("OutLookServiceURL").toString()));
		service.setTraceEnabled(true);
		return service;
	}

	/**
	 * 发送邮件到 outlook日历
	 */
	private static Map<String, String> sendMeetBook(ExchangeService service, MessageInfo messageInfo) {
		Map<String, String> msgMap = new HashMap<>();
		msgMap.put(IS_OK, "0"); //  0 : 成功 ， 1：失败
		msgMap.put(IS_ERROR_MESSAGE, "");

		Appointment appointment = null;
		String itemId = "";
		try {
			appointment = new Appointment(service);
			// 主题/标题
			appointment.setSubject(messageInfo.getSubject());
			// 正文内容,设置纯文本正文
			appointment.setBody(MessageBody.getMessageBodyFromText(messageInfo.getBodyMessage()));

			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
			format.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
			OlsonTimeZoneDefinition timezone = new OlsonTimeZoneDefinition(TimeZone.getTimeZone("Asia/Shanghai"));
			appointment.setEndTimeZone(timezone);
			appointment.setStartTimeZone(timezone);

			// 指定起始和结束时间
			// appointment.setStart(new Date());
			// appointment.setEnd(new Date());
			appointment.setStart(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(messageInfo.getStartTime()));
			appointment.setEnd(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(messageInfo.getEndTime()));
			// 会议地点
			appointment.setLocation(messageInfo.getLocation());

			// RequiredAttendees ：必须参加的员工的邮箱, 可以添加多个
			List<String> emailList = messageInfo.getEmailTo();
			if (emailList != null && emailList.size() > 0) {
				for (String email : emailList) {
					appointment.getRequiredAttendees().add(email);
				}
			}

			// appointment.getRequiredAttendees().add("user1@qq.com");
			// appointment.getRequiredAttendees().add("user2@qq.com");

			// OptionalAttendees： 可选参与者， 可选参加的员工的邮箱
			List<String> optionalEmailTo = messageInfo.getOptionalEmailTo();
			if (optionalEmailTo != null && optionalEmailTo.size() > 0) {
				for (String email : optionalEmailTo) {
					appointment.getOptionalAttendees().add(email);
				}
			}
			// 添加文件附件
			// appointment.getAttachments().addFileAttachment(fileName,getFile(fileUrl));
			// appointment.update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendToAllAndSaveCopy);

			// ReminderMinutesBeforeStart：会议前提醒时间（分钟） ,会议提前15分钟提醒
			appointment.setReminderMinutesBeforeStart(15);
			appointment.save(SendInvitationsMode.SendToAllAndSaveCopy);

			// System.out.println("appointment.getId() ==> " + appointment.getId());

			Item item = Item.bind(service, appointment.getId(), new PropertySet(ItemSchema.Subject));
			// 这里创建一个item之后，如果要修改会议，一定要保存好这个item.getId(),否则找不到会议，不能修改
			// System.out.println("会议创建成功： " + item.getSubject());

			itemId = item.getId().toString();
			appointment.load();

			appointment.setStart(format.parse(format.format(appointment.getStart())));
			appointment.setEnd(format.parse(format.format(appointment.getEnd())));
			appointment.update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendToAllAndSaveCopy);
			msgMap.put(IS_OK, "0"); //  0 : 成功 ， 1：失败
			msgMap.put(IS_OK_MESSAGE, itemId);
		} catch (Exception e) {
			msgMap.put(IS_OK, "1"); //  0 : 成功 ， 1：失败
			msgMap.put(IS_ERROR_MESSAGE, e.getMessage());
		}

		return msgMap;
	}

	/**
	 * 取消 outlook 日历
	 */
	private static int cancelMeetBook(ExchangeService service, String itemId, String remark) {
		Appointment appointment = null;
		int isOk = 0;
		try {
			appointment = Appointment.bind(service, ItemId.getItemIdFromString(itemId), new PropertySet());
			appointment.cancelMeeting(remark);
			appointment.update(ConflictResolutionMode.AlwaysOverwrite);
			// appointment.delete(DeleteMode.MoveToDeletedItems, SendCancellationsMode.SendToAllAndSaveCopy);
		} catch (Exception e) {
			isOk = 1;
		}
		return isOk;
	}

	/**
	 * 暂时未使用
	 */
	public String sendCycleMeetBook(ExchangeService service, MessageInfo messageInfo) {
		Appointment appointment = null;
		String itemId = "";
		try {
			appointment = new Appointment(service);

			// 主题/标题
			appointment.setSubject(messageInfo.getSubject());
			// 正文内容,设置纯文本正文
			appointment.setBody(MessageBody.getMessageBodyFromText(messageInfo.getBodyMessage()));
			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");

			OlsonTimeZoneDefinition timezone = new OlsonTimeZoneDefinition(TimeZone.getTimeZone("Asia/Shanghai"));
			appointment.setEndTimeZone(timezone);
			appointment.setStartTimeZone(timezone);

			// 指定起始和结束时间
			// appointment.setStart(new Date());
			// appointment.setEnd(new Date());
			appointment.setStart(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(messageInfo.getStartTime()));
			appointment.setEnd(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(messageInfo.getEndTime()));
			// 会议地点
			appointment.setLocation(messageInfo.getLocation());

			if ("1".equals("")) {
				Recurrence recurrence = new Recurrence.DailyPattern(new Date(), 1);
				recurrence.setNumberOfOccurrences(1);
				appointment.setRecurrence(recurrence);
			} else if ("3".equals("")) {
				Recurrence recurrence = new Recurrence.MonthlyPattern(new Date(), 1, 1);
				recurrence.setNumberOfOccurrences(1);
				appointment.setRecurrence(recurrence);
			} else if ("2".equals("")) {
				String[] weekDayArray = new String[] {};
				DayOfTheWeek[] dayOfTheWeeks = new DayOfTheWeek[weekDayArray.length];
				for (int a = 0; a < weekDayArray.length; a++) {
					if ("1".equals(weekDayArray[a].toString())) {
						dayOfTheWeeks[a] = DayOfTheWeek.Monday;
					} else if ("2".equals(weekDayArray[a].toString())) {
						dayOfTheWeeks[a] = DayOfTheWeek.Tuesday;
					} else if ("3".equals(weekDayArray[a].toString())) {
						dayOfTheWeeks[a] = DayOfTheWeek.Wednesday;
					} else if ("4".equals(weekDayArray[a].toString())) {
						dayOfTheWeeks[a] = DayOfTheWeek.Thursday;
					} else if ("5".equals(weekDayArray[a].toString())) {
						dayOfTheWeeks[a] = DayOfTheWeek.Friday;
					} else if ("6".equals(weekDayArray[a].toString())) {
						dayOfTheWeeks[a] = DayOfTheWeek.Saturday;
					} else if ("0".equals(weekDayArray[a].toString())) {
						dayOfTheWeeks[a] = DayOfTheWeek.Sunday;
					}
				}
				Recurrence recurrence = new Recurrence.WeeklyPattern(new Date(), 1, dayOfTheWeeks);
				recurrence.setNumberOfOccurrences(1);
				appointment.setRecurrence(recurrence);
			} else if ("4".equals("")) {
				String weekDay = "";
				DayOfTheWeek weekday = DayOfTheWeek.Monday;
				if ("1".equals(weekDay)) {
					weekday = DayOfTheWeek.Monday;
				} else if ("2".equals(weekDay)) {
					weekday = DayOfTheWeek.Tuesday;
				} else if ("3".equals(weekDay)) {
					weekday = DayOfTheWeek.Wednesday;
				} else if ("4".equals(weekDay)) {
					weekday = DayOfTheWeek.Thursday;
				} else if ("5".equals(weekDay)) {
					weekday = DayOfTheWeek.Friday;
				} else if ("6".equals(weekDay)) {
					weekday = DayOfTheWeek.Saturday;
				} else if ("0".equals(weekDay)) {
					weekday = DayOfTheWeek.Sunday;
				}
				DayOfTheWeekIndex monthday = DayOfTheWeekIndex.First;
				if ("0".equals("")) {
					monthday = DayOfTheWeekIndex.Last;
				} else if ("1".equals("order.getMonthDay()")) {
					monthday = DayOfTheWeekIndex.First;
				} else if ("2".equals("order.getMonthDay()")) {
					monthday = DayOfTheWeekIndex.Second;
				} else if ("3".equals("order.getMonthDay()")) {
					monthday = DayOfTheWeekIndex.Third;
				} else if ("4".equals("order.getMonthDay()")) {
					monthday = DayOfTheWeekIndex.Fourth;
				}
				Recurrence recurrence = new Recurrence.RelativeMonthlyPattern(new Date(), 1, weekday, monthday);
				recurrence.setNumberOfOccurrences(1);
				appointment.setRecurrence(recurrence);
			}
			// 添加附件
			// appointment.getAttachments().addFileAttachment("fileName,getFile(fileUrl)");

			// 会议提前15分钟提醒
			appointment.setReminderMinutesBeforeStart(15);
			appointment.save(SendInvitationsMode.SendToAllAndSaveCopy);
			System.out.println(appointment.getId());
			Item item = Item.bind(service, appointment.getId(), new PropertySet(ItemSchema.Subject));
			// 这里创建一个item之后，如果要修改会议，一定要保存好这个item.getId(),否则找不到会议，不能修改
			System.out.println("会议创建成功： " + item.getSubject());
			itemId = item.getId().toString();
			appointment.load();
			// 添加邮箱
			appointment.getRequiredAttendees().add("user.getEmail()");
			appointment.setStart(format.parse(format.format(appointment.getStart())));
			appointment.setEnd(format.parse(format.format(appointment.getEnd())));
			appointment.update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendToAllAndSaveCopy);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return itemId;
	}

}
